/*----------------------------------------------------------------------*
 *	CLASS:		Qt3Resolution
 *	Quantum Tic Tac Toe
 *	Copyright (c) 2004-2009 Novatia Labs, Inc.  All rights reserved.
 *----------------------------------------------------------------------*/

package com.novatialabs.qttt.engine.impl;

import com.novatialabs.qttt.engine.Qt3MoveNotInSquareException;
import com.novatialabs.qttt.engine.Qt3MoveNotInTangleException;
import com.novatialabs.qttt.engine.Qt3Player;

/**
 * Resolution keeps track of a entanglement-resolution in a Quantum Tic Tac
 * Toe game.
 *
 * @Author	Duane Gibson
 * @Author Friendly development resources cheerfully provided by Charles Phares.
 * @Author	$Author$
 * @Version	$Revision$
 */

/*package*/ class Qt3Resolution
    extends Qt3Step
{

    public static final int	Resolution_UNDECIDED		= 0;
    public static final int	Resolution_FIRST_SQUARE		= 1;
    public static final int	Resolution_SECOND_SQUARE	= 2;
    public static final int	Resolution_NEEDED		= 3;
    public static final int	Resolution_NONE			= 4;

   /**
    * The state of the resolution.
    */
    private int			resolution;	// see Resolution_* constants.


   /*-------------------------------------------------------------------*
    *	CONSTRUCTOR:	Qt3Resolution()
    *	AUTHOR:		Duane Gibson
    *	CREATION DATE:	Sat Jun 19 15:14:55 PDT 2004
    *-------------------------------------------------------------------*/
   /**
    * Constructs a resolution.
    */

    /*package*/ Qt3Resolution(
	int		moveNum,
	Qt3Step		prevStep
	)
    {
	super(moveNum, prevStep);

    } // Qt3Resolution()

   /*-------------------------------------------------------------------*
    *	METHOD:		clearStep()
    *	AUTHOR:		Duane Gibson
    *	CREATION DATE:	Sat Jun 19 15:15:54 PDT 2004
    *-------------------------------------------------------------------*/
   /**
    * Clears this resolution object to an initial state.
    */

    protected void clearStep() {

	this.resolution = Resolution_UNDECIDED;

    } // clearStep()

   /*-------------------------------------------------------------------*
    *	METHOD:		appendAsString()
    *	AUTHOR:		Duane Gibson
    *	CREATION DATE:	Sat Jun 19 15:19:54 PDT 2004
    *-------------------------------------------------------------------*/
   /**
    * Appends a representation of this object as a String to the specified
    * string buffer.
    *
    * @param	buf	string buffer to append to.
    */

    /*package*/ void appendAsString(
	StringBuffer	buf
	)
    {

	switch ( this.resolution ) {

	  case Resolution_FIRST_SQUARE:
	    buf.append('<');
	    break;

	  case Resolution_SECOND_SQUARE:
	    buf.append('>');
	    break;

	  case Resolution_NONE:
	    buf.append('-');
	    break;

	  case Resolution_NEEDED:
	    buf.append('?');
	    break;

	  case Resolution_UNDECIDED:
	  default:
	    buf.append(' ');
	    break;
	}

    } // appendAsString()

   /*-------------------------------------------------------------------*
    *	METHOD:		getPlayer()
    *	AUTHOR:		Duane Gibson
    *	CREATION DATE:	Sat Jun 19 15:17:37 PDT 2004
    *-------------------------------------------------------------------*/
   /**
    * Returns the player who decides this resolution.
    */

    public Qt3Player getPlayer() {
	return (((this.getMoveNumber() % 2) == 1)
		? Qt3Player.O
		: Qt3Player.X);
    } // getPlayer()

   /*-------------------------------------------------------------------*
    *	METHOD:		isRedoable()
    *	AUTHOR:		Duane Gibson
    *	CREATION DATE:	Sat Jun 19 15:25:34 PDT 2004
    *-------------------------------------------------------------------*/
   /**
    * Returns whether this move can be "redone".
    */

    /*package*/ boolean isRedoable()
    {

	switch ( this.resolution ) {

	    case Resolution_NONE:
	    case Resolution_FIRST_SQUARE:
	    case Resolution_SECOND_SQUARE:
		return true;

	    default:
	    case Resolution_UNDECIDED:
	    case Resolution_NEEDED:
		return false;

	}

    } // isRedoable()

   /*-------------------------------------------------------------------*
    *	METHOD:		isAutomatic()
    *	AUTHOR:		Duane Gibson
    *	CREATION DATE:	Sat Jun 19 17:46:55 PDT 2004
    *-------------------------------------------------------------------*/
   /**
    * Returns whether this step is "automatic".
    * This means that no user input is required, the completion of the step
    * is automatically implied by the state of the game.
    * Note that a step must be redo-able for it to be automatic.
    */

    /*package*/ boolean isAutomatic()
    {

	if ( this.resolution == Resolution_UNDECIDED ) {
	    /*DRG DEBUG*/System.err.println("Resolution is undecided...");
	    // Determine whether this resolution is required based on
	    // the previous move.
	    if ( this.getPreviousStep().getState().hasSelfRefEntanglement() ) {
		/*DRG DEBUG*/System.err.println("... resolution needed.");
		this.resolution = Resolution_NEEDED;
	    } else {
		/*DRG DEBUG*/System.err.println("... resolution none.");
		this.resolution = Resolution_NONE;
	    }
	}

	return (this.resolution == Resolution_NONE);

    } // isAutomatic()

   /*-------------------------------------------------------------------*
    *	METHOD:		getResolution()
    *	AUTHOR:		Duane Gibson
    *	CREATION DATE:	Sat Jun 19 15:25:49 PDT 2004
    *-------------------------------------------------------------------*/
   /**
    * Returns the resolution of this move.
    * The resolution will be one of the constant Resolution_* constants.
    */

    public int getResolution() {
	return this.resolution;
    } // getResolution()

   /*-------------------------------------------------------------------*
    *	METHOD:		setResolution()
    *	AUTHOR:		Duane Gibson
    *	CREATION DATE:	Sat Jun 19 16:02:10 PDT 2004
    *-------------------------------------------------------------------*/
   /**
    * Sets the resolution for this move.
    *
    * @param	resolveToFirstSquare	whether resolution is to first
    *					square (<code>true</code>) or
    *					second square (<code>false</code>).
    */

    /*package*/ void setResolution( boolean resolveToFirstSquare )
    {

	if ( this.resolution != Resolution_NEEDED ) {
	    throw new IllegalStateException();
	}

	if ( resolveToFirstSquare ) {
	    this.resolution = Resolution_FIRST_SQUARE;
	} else {
	    this.resolution = Resolution_SECOND_SQUARE;
	}

    } // setResolution()

   /*-------------------------------------------------------------------*
    *	METHOD:		normalizeResolution()
    *	AUTHOR:		Duane Gibson
    *	CREATION DATE:	Tue Jan 11 16:47:27 PST 2005
    *-------------------------------------------------------------------*/
   /**
    * Normalize a resolution (square-move) description into a boolean
    * indication of which square was chosen in the last move of the
    * cycle.
    *
    * @param	squareIndex	index of the square in which a resolution
    *				was chosen.
    * @param	moveNumber	number of the move chosen to occupy the
    *				square.
    * @return	whether resolution is to first square (<code>true</code>)
    *		or second square (<code>false</code>).
    * @throws	Qt3MoveNotInTangleException 
    *		if the move selected is not part of the tangle that must
    *		be resolved. 
    * @throws	Qt3MoveNotInSquareException
    *		if the move selected was not made in the square indicated. 
    */

    /*package*/ boolean normalizeResolution(
	int	squareIndex,
	int	moveNumber
	)
	throws Qt3MoveNotInTangleException, Qt3MoveNotInSquareException
    {
	final Qt3Tangle tangle = this.getPreviousStep().getState().getTangle();
	return tangle.normalizeResolution(squareIndex, moveNumber);
    } // normalizeResolution()

   /*-------------------------------------------------------------------*
    *	METHOD:		transformState()
    *	AUTHOR:		Duane Gibson
    *	CREATION DATE:	Sat Jan  8 19:29:42 PST 2005
    *-------------------------------------------------------------------*/
   /**
    * Sets the resolution for this move.
    *
    * @param	resolveToFirstSquare	whether resolution is to first
    *					square (<code>true</code>) or
    *					second square (<code>false</code>).
    */

    protected Qt3State transformState(
	Qt3State	prevState
	)
    {
	switch ( this.resolution ) {

	    case Resolution_UNDECIDED:
	    case Resolution_NEEDED:
	    default:
		// TODO: report IllegalStateException
		// FALL-THROUGH 
	    case Resolution_NONE:
		// No change, use previous state.
		return prevState;

	    case Resolution_FIRST_SQUARE:
		{
		// resolve tangle to first square in previous Move ..
		Qt3State newState = new Qt3State(prevState, true/*1stSq*/);
		return newState;
		}

	    case Resolution_SECOND_SQUARE:
		{
		// resolve tangle to second square in previous Move ..
		Qt3State newState = new Qt3State(prevState, false/*2ndSq*/);
		return newState;
		}

	}

    } // transformState()

} // class Qt3Resolution

